import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
import 'functional_x.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:flex_seed_scheme/flex_seed_scheme.dart' as flex;


part 'app_color_scheme.g.dart';
part 'app_color_scheme.freezed.dart';

@riverpod
class AppColorScheme extends _$AppColorScheme {
  @override
  BasilColorScheme build(Brightness brightness, String primary, {String? secondary, String? tertiary, String? neutral}) {
    return BasilColorScheme(brightness, primary.toColor, secondaryColor: secondary?.toColor, tertiaryColor: tertiary?.toColor, neutralColor: (neutral)?.toColor);
  }
}

class BasilColorScheme extends ThemeExtension<BasilColorScheme> {
  final Brightness brightness;
  final Color primaryColor;
  final Color? secondaryColor;
  final Color? tertiaryColor;
  final Color? neutralColor;

  BasilColorScheme(this.brightness, this.primaryColor, {this.secondaryColor, this.tertiaryColor, this.neutralColor});

  ColorScheme toColorScheme() {
    final luminance = primaryColor.computeLuminance();
    return flex.SeedColorScheme.fromSeeds(
      brightness: brightness,
      // primary: brightness == Brightness.light ? primaryColor : null,
      primaryKey: primaryColor,
      secondaryKey: secondaryColor,
      onPrimary: Colors.white,  //todo BasilColorScheme后续是否需要拆分为项目配置
      error: Colors.red,
      onError: Colors.white,
      tertiaryKey: tertiaryColor,
      tones: flex.FlexTones.jolly(brightness).copyWith(
        primaryTone: brightness == Brightness.light ? (luminance > 0.2 ? 65 : null) : (luminance > 0.2 ? 58 : null),
        surfaceTone: brightness == Brightness.light ? 100 : null,
        backgroundTone: brightness == Brightness.light ? 100 : null,
      ),
    );
  }

  @override
  ThemeExtension<BasilColorScheme> copyWith({Brightness? brightness, Color? primaryColor, Color? secondaryColor, Color? tertiaryColor, Color? neutralColor}) {
    return BasilColorScheme(
      brightness ?? this.brightness,
      primaryColor ?? this.primaryColor,
      secondaryColor: secondaryColor ?? this.secondaryColor,
      tertiaryColor: tertiaryColor ?? this.tertiaryColor,
      neutralColor: neutralColor ?? this.neutralColor,
    );
  }

  @override
  ThemeExtension<BasilColorScheme> lerp(covariant ThemeExtension<BasilColorScheme>? other, double t) {
    if (other is! BasilColorScheme) return this;
    return BasilColorScheme(
      other.brightness,
      Color.lerp(primaryColor, other.primaryColor, t)!,
      secondaryColor: Color.lerp(secondaryColor, other.secondaryColor, t),
      tertiaryColor: Color.lerp(tertiaryColor, other.tertiaryColor, t),
      neutralColor: Color.lerp(neutralColor, other.neutralColor, t),
    );
  }
}

extension ColorX on String {
  Color get toColor {
    int color = int.parse(this, radix: 16);
    int a = color >> (8 * 3);
    int r = color >> (8 * 2) & 0xFF;
    int g = color >> (8 * 1) & 0xFF;
    int b = color & 0xFF;
    return Color.fromARGB(a, r, g, b);
  }
  Color get hexToColor {
    if (length == 7) {
      final target = substring(1, 7);
      if (int.tryParse(target, radix: 16) == null) {
        throw Exception("color解析失败! ");
      } else {
        return Color(int.parse(target, radix: 16) + 0xFF000000);
      }
    } else if (length == 9) {
      final target = substring(1, 9);
      if (int.tryParse(target, radix: 16) == null) {
        throw Exception("color解析失败! ");
      } else {
        return Color(int.parse(target, radix: 16) + 0xFF000000);
      }
    }
    throw Exception("color 长度不正确!");
  }
}

@freezed
class ColorGroup with _$ColorGroup {
  const factory ColorGroup({
    required Color color,
    required Color onColor,
    required Color containerColor,
    required Color onContainerColor,
  }) = _ColorGroup;

  factory ColorGroup.fromHexString(String hex, Brightness brightness, bool deepColor) => Brightness.light == brightness
      ? CorePalette.of(hex.toColor.value).let(
          (it) => ColorGroup(
            color: Color(it.primary.get(40)),
            onColor: Color(it.primary.get(100)),
            containerColor: Color(it.primary.get(95)).withOpacity(0.8),
            onContainerColor: Color(it.primary.get(deepColor ? 60 : 75)),
          ),
        )
      : CorePalette.of(hex.toColor.value).let(
          (it) => ColorGroup(
            color: Color(it.primary.get(80)),
            onColor: Color(it.primary.get(20)),
            containerColor: Color(it.primary.get(50)).withOpacity(0.5),
            onContainerColor: Color(it.primary.get(95)),
          ),
        );
}